﻿
namespace XmlSchemaProvider.Web
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server;
    using AbstraX.ServerInterfaces;
    using XmlSchemaProvider.Web;
    using System.Diagnostics;
    using MvvmTreeView;
    using AbstraX.Contracts;
    using Schemas = XmlSchemaProvider.Web.Entities;
    using XmlSchemaProvider.Web.Entities;
    using System.Linq.Dynamic;
    using AbstraX.TypeMappings;
    using System.IO;
    using Microsoft.Practices.Unity;

    //  SchemasRoot
    //    Solution
    //      Project
    //        Schema
    //          Element
    //            Attribute

    [EnableClientAccess()]
    public class XmlSchemaProviderService : DomainService, IAbstraXProviderService
    {
        public IDomainHostApplication DomainServiceHostApplication { get; set; }

        [Invoke]
        public string GetRootID()
        {
            return new SchemasRoot(this).ID;
        }

        public SchemasRoot GetRoots()
        {
            return new SchemasRoot(this);
        }

        [Query]
        public IQueryable<Solution> GetSolutions()
        {
            Debug.WriteLine("Loading solutions");

            var hierarchy = new SchemaProviderHierarchy<Schemas.Solution>(this);
            var results = hierarchy.AsQueryable();

            return results;
        }

        [Query]
        public IQueryable<Project> GetProjects()
        {
            Debug.WriteLine("Loading projects");

            var hierarchy = new SchemaProviderHierarchy<Schemas.Project>(this);
            var results = hierarchy.AsQueryable();

            return results;
        }

        [Query]
        public IQueryable<Schema> GetSchemas()
        {
            Debug.WriteLine("Loading schemas");

            var hierarchy = new SchemaProviderHierarchy<Schemas.Schema>(this);
            var results = hierarchy.AsQueryable();

            return results;
        }

        [Query]
        public IQueryable<SchemaElement> GetElements()
        {
            Debug.WriteLine("Loading elements");

            var hierarchy = new SchemaProviderHierarchy<Schemas.SchemaElement>(this);
            var results = hierarchy.AsQueryable();

            return results;
        }

        [Query]
        public IQueryable<Schemas.SchemaAttribute> GetAttributes()
        {
            Debug.WriteLine("Loading attributes");

            var hierarchy = new SchemaProviderHierarchy<Schemas.SchemaAttribute>(this);
            var results = hierarchy.AsQueryable();

            return results;
        }

        [Query]
        public IQueryable<Solution> GetSolutionsForSchemasRoot(string parentID)
        {
            Debug.WriteLine("Loading solutions for '" + parentID + "'");

            var hierarchy = new SchemaProviderHierarchy<Schemas.Solution>(this);
            var results = hierarchy.AsQueryable().Where(a => a.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<Project> GetProjectsForSolution(string parentID)
        {
            Debug.WriteLine("Loading projects for '" + parentID + "'");

            var hierarchy = new SchemaProviderHierarchy<Schemas.Project>(this);
            var results = hierarchy.AsQueryable().Where(a => a.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<Schema> GetSchemasForProject(string parentID)
        {
            Debug.WriteLine("Loading schemas for '" + parentID + "'");

            var hierarchy = new SchemaProviderHierarchy<Schemas.Schema>(this);
            var results = hierarchy.AsQueryable().Where(a => a.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<SchemaElement> GetElementsForSchema(string parentID)
        {
            Debug.WriteLine("Loading elements for '" + parentID + "'");

            var hierarchy = new SchemaProviderHierarchy<Schemas.SchemaElement>(this);
            var results = hierarchy.AsQueryable().Where(a => a.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<Schemas.SchemaAttribute> GetAttributesForSchemaElement(string parentID)
        {
            Debug.WriteLine("Loading attributes for '" + parentID + "'");

            var hierarchy = new SchemaProviderHierarchy<Schemas.SchemaAttribute>(this);
            var results = hierarchy.AsQueryable().Where(a => a.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<Schemas.SchemaElement> GetElementsForSchemaElement(string parentID)
        {
            Debug.WriteLine("Loading child elements for '" + parentID + "'");

            var hierarchy = new SchemaProviderHierarchy<Schemas.SchemaElement>(this);
            var results = hierarchy.AsQueryable().Where(a => a.ParentID == parentID);

            return results;
        }

        [Invoke]
        public byte[] GetImageForFolder(string folderKey)
        {
            Debug.WriteLine("Loading images for '" + folderKey + "'");

            var stream = this.GetType().Assembly.GetManifestResourceStream(folderKey);
            var bytes = new byte[stream.Length];

            stream.Read(bytes, 0, (int)stream.Length);

            return bytes;
        }

        [Invoke]
        public byte[] GetImageForItemType(string itemTypeName)
        {
            Debug.WriteLine("Loading images for '" + itemTypeName + "'");

            var attribute = (NodeImageAttribute)System.Type.GetType(itemTypeName).GetCustomAttributes(true).FirstOrDefault(a => a is NodeImageAttribute);

            var stream = this.GetType().Assembly.GetManifestResourceStream(attribute.ImagePath);
            var bytes = new byte[stream.Length];

            stream.Read(bytes, 0, (int)stream.Length);

            return bytes;
        }

        [Invoke]
        public byte[] GetImageForUrl(string url)
        {
            Debug.WriteLine("Loading images for '" + url + "'");

            var stream = this.GetType().Assembly.GetManifestResourceStream(url);
            var bytes = new byte[stream.Length];

            stream.Read(bytes, 0, (int)stream.Length);

            return bytes;
        }

        [Invoke]
        public ContainerType GetAllowableContainerTypes(string id)
        {
            var baseObject = this.GenerateByID(id);

            if (baseObject is SchemaElement)
            {
                var element = (SchemaElement)baseObject;

                if (element.ChildElements.Count() == 1)
                {
                    return ContainerType.Construct | ContainerType.Property;
                }
                else
                {
                    return ContainerType.Construct;
                }
            }
            else
            {
                return ContainerType.NotSet;
            }
        }

        [Invoke]
        public ConstructType GetAllowableConstructTypes(string id)
        {
            var baseObject = this.GenerateByID(id);

            if (baseObject is SchemaElement)
            {
                return ConstructType.Class | ConstructType.Struct;
            }
            else
            {
                return ConstructType.NotSet;
            }
        }

        public IBase GenerateByID(string id)
        {
            return AbstraXExtensions.GenerateByID(this, id);
        }

        public SortedList<float, IPipelineStep> InitialPipelineSteps
        {
            get
            {
                var step = this.DomainServiceHostApplication.PipelineContainer.Resolve<IPipelineStep>("XmlSchemasStep");
                var list = new SortedList<float, IPipelineStep>();

                list.Add(0, step);

                return list;
            }
        }
    }
}


